﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Maps.MapControl.WPF;

namespace Shrestha.Trigraph
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class MapDisplay : Window, IObserver<WorkingSet>
    {
        private LocationRect lr;
        private WorkingSet currentSet;
        private MainWindow mainWindow;

        private bool changed = false;

        public bool Changed
        {
            get { return changed; }
            set { changed = value; }
        }

        private IDisposable unsubscriber;

        public MapDisplay(MainWindow m)
        {
            InitializeComponent();
            mainWindow = m;
        }

        public MapDisplay(WorkingSet working, MainWindow m)
        {
            InitializeComponent();
            mainWindow = m;
            currentSet = working;
            
            this.Loaded += new RoutedEventHandler(Map_Loaded);

        }

        private void LoadMap()
        {
            lr = new LocationRect(new TriEvent(currentSet.MaxDbLat, currentSet.MaxDbLng), new TriEvent(currentSet.MinDbLat, currentSet.MinDbLng));
            try
            {
                myMap.SetView(lr);
                foreach (TriEvent te in currentSet.TriEventList)
                {
                    //PlaceDot(te);
                    PlaceIcon(te);
                }
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            };
        }

        private void Map_Loaded(object sender, RoutedEventArgs e)
        {
            LoadMap();
        }

        private void PlaceDot(Location location)
        {
            Ellipse dot = new Ellipse();
            dot.Stroke = Brushes.Red;
            double radius = 5.0;
            dot.Width = radius * 2;
            dot.Height = radius * 2;
            ToolTip tt = new ToolTip();
            tt.Content = "Location = " + location;
            dot.ToolTip = tt;
            Point p0 = myMap.LocationToViewportPoint(location);
            Point p1 = new Point(p0.X - radius, p0.Y - radius);
            Location loc = myMap.ViewportPointToLocation(p1);
            MapLayer.SetPosition(dot, loc);
            myMap.Children.Add(dot);
        }

        private void PlaceIcon(Location location)
        {
            MapLayer imageLayer = new MapLayer();
            Image image = new Image();
            image.Height = 37;
            //Define the URI location of the image
            BitmapImage myBitmapImage = new BitmapImage();
            myBitmapImage.BeginInit();
            String s = Environment.CurrentDirectory;
            myBitmapImage.UriSource = new Uri("accident.png",UriKind.Relative);
            myBitmapImage.DecodePixelHeight = 37;
            myBitmapImage.EndInit();
            image.Source = myBitmapImage;
            image.Opacity = 0.5;
            image.Stretch = System.Windows.Media.Stretch.None;

            //Center the image around the location specified
            PositionOrigin position = PositionOrigin.BottomCenter;

            //Add the image to the defined map layer
            imageLayer.AddChild(image, location, position);
            //Add the image layer to the map
            myMap.Children.Add(imageLayer);
        }

        private void DrawLine(Location start, Location finish)
        {
            LocationCollection coll = new LocationCollection();
            coll.Add(start);
            coll.Add(finish);
            MapPolyline line = new MapPolyline();
            line.Stroke = new SolidColorBrush(Colors.Orange);
            line.StrokeThickness = 3.0;
            line.Locations = coll;
            myMap.Children.Add(line);
        }

        private void DrawCurve(Location start, Location finish)
        {
            MapPolyline curve = new MapPolyline();
            curve.Stroke = new SolidColorBrush(Colors.Magenta);
            curve.StrokeThickness = 3.0;
            curve.StrokeDashArray = new DoubleCollection(new double[] { 5, 2 });
            curve.Opacity = 1.0;

            LocationCollection coll = new LocationCollection();

            // Compute control point
            Point p1 = myMap.LocationToViewportPoint(start);
            Point p2 = myMap.LocationToViewportPoint(finish);

            double boundingBoxHalfWidth = (p2.X - p1.X) / 2.0;
            double boundingBoxHalfHeight = (p1.Y - p2.Y) / 2.0;

            double centerX = (p1.X + p2.X) / 2.0;
            double centerY = (p1.Y + p2.Y) / 2.0;

            double xScale = 1.0;
            double yScale = 1.0;

            double controlX = centerX - (xScale * boundingBoxHalfWidth);
            double controlY = centerY - (yScale * boundingBoxHalfHeight);

            Point controlPt = new Point(controlX, controlY);
            Location controlLoc = myMap.ViewportPointToLocation(controlPt);

            // Compute intermediate Locations using the control point
            int numSegments = 31;
            double tDelta = 1.0 / numSegments;
            for (double t = 0.0; t <= 1.0; t += tDelta) // Danger!
            {
                // x coordinate (longitudes)
                double a = (1.0 - t) * (1.0 - t) * start.Longitude;
                double b = 2.0 * (1.0 - t) * t * controlLoc.Longitude;
                double c = t * t * finish.Longitude;
                double Blon = a + b + c;

                // y coordinate (latitudes)
                a = (1.0 - t) * (1.0 - t) * start.Latitude;
                b = 2.0 * (1.0 - t) * t * controlLoc.Latitude;
                c = t * t * finish.Latitude;
                double Blat = a + b + c;

                coll.Add(new Location(Blat, Blon));
            }

            curve.Locations = coll;
            myMap.Children.Add(curve);
        }


        private void myMap_ViewChangeEnd(object sender, MapEventArgs e)
        {
            Map m = sender as Map;

            LocationRect lx = m.BoundingRectangle;
            double minLat, maxLat, minLng, maxLng;
            minLat = lx.North > lx.South ? lx.South : lx.North;
            maxLat = lx.North > lx.South ? lx.North : lx.South;
            minLng = lx.East > lx.West ? lx.West : lx.East;
            maxLng = lx.East > lx.West ? lx.East : lx.West;
            //currentSet = Filter.GetFiltered(
            //    Math.Round(minLat, 5),
            //    Math.Round(maxLat, 5),
            //    Math.Round(minLng, 5),
            //    Math.Round(maxLng, 5),
            //    mainWindow.MaximalSet);
            currentSet = Filter.GetFiltered(
                Math.Round(minLat, 5),
                Math.Round(maxLat, 5),
                Math.Round(minLng, 5),
                Math.Round(maxLng, 5),
                currentSet.IsClustered);
            mainWindow.UpdateWorkingSets(currentSet);

        }

        public void OnCompleted()
        {
            throw new NotImplementedException();
        }

        public void OnError(Exception error)
        {
            throw new NotImplementedException();
        }

        public void OnNext(WorkingSet value)
        {
            if (currentSet.CompareTo(value) != 0)
            {
                currentSet = value;
                LoadMap();
            }
        }

        public virtual void Subscribe(IObservable<WorkingSet> provider)
        {
            if (provider != null)
                unsubscriber = provider.Subscribe(this);
        }

        public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
        }
    }
}
